package com.ruoyi.apduParse.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.apduParse.constant.AidConstant;
import com.ruoyi.apduParse.domain.AidTable;
import com.ruoyi.apduParse.dto.AidInfo;
import com.ruoyi.apduParse.dto.ApduInfoDto;
import com.ruoyi.apduParse.dto.SentenceFactoryDto;
import com.ruoyi.apduParse.factory.SentenceStrategyFactory;
import com.ruoyi.apduParse.service.IAidTableService;
import com.ruoyi.apduParse.strategy.SentenceStrategy;
import com.ruoyi.apduParse.vo.ApduParseVo;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.apduParse.domain.ApduTable;
import com.ruoyi.apduParse.vo.ApduTableVo;
import com.ruoyi.apduParse.mapper.ApduTableMapper;
import com.ruoyi.apduParse.service.IApduTableService;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * APDU指令Service业务层处理
 *
 * @author 刘梦豪
 * @date 2024-10-25
 */
@Service
@Slf4j
public class ApduTableServiceImpl extends ServiceImpl<ApduTableMapper, ApduTable> implements IApduTableService {

    @Autowired
    private IAidTableService aidTableService;

    @Override
    public TableDataInfo<ApduTableVo> queryList(ApduTableVo entity) {
        return PageUtils.buildDataInfo(this.baseMapper.queryList(PageUtils.buildPage(), entity));
    }

    @Override
    public List<ApduTableVo> queryAll(ApduTableVo entity) {
        return this.baseMapper.queryList(entity);
    }

    @Override
    public ApduTableVo queryById(Long id) {
        return this.baseMapper.queryById(id);
    }

    @Override
    public AjaxResult parseApdu(ApduInfoDto apduInfo) {
        //健壮性判断
        if (apduInfo == null || StringUtils.isNull(apduInfo.getApdu())) {
            return AjaxResult.error("指令为空");
        }

        //获取指令
        String apdu = apduInfo.getApdu();

        //查询指令大致用途
        ApduTable apduTable = getApduTable(apduInfo);

        if (apduTable == null){
         return AjaxResult.error("未查询到该指令用途，请传入正确的指令");
        }

        //查询相关AID
        //1.获取AID
        AidTable aidTable = getAid(apduInfo);
        if (aidTable == null) {
            return AjaxResult.error("未找到对应AID");
        }
        log.info("指令中可能存在的aid：{}", aidTable);

        //判断指令中存在哪些Aid，全部都判断一下，将存在的aid放入到集合中
        List<AidInfo> aidInfos = getAidInfo(aidTable, apduTable, apdu);

        if (CollectionUtil.isNotEmpty(aidInfos)){
            //指令中存在aid，需要获取各个aid的用途以及优先级，然后进行拼接返回
            return haveAidResult(aidInfos, apduTable, apdu);
        }else {
            //指令中不存在aid，只需要分析作用即可
            return emptyAidResult(apduTable,apdu);
        }

    }

    /**
     * 获取指令大致用途
     * @param apduInfo
     * @return
     */
    private ApduTable getApduTable(ApduInfoDto apduInfo){
        //获取指令
        String apdu = apduInfo.getApdu();
        log.info("需要解析的指令：{}", apdu);

        //解析指令用途
        //1.截取INS和P1
        String INS = apdu.substring(2, 4);
        String P1 = apdu.substring(4, 6);

        log.info("INS:{}", INS);
        log.info("P1:{}", P1);

        ApduTable apduTable = null;

        //2.根据INS查询指令
        List<ApduTable> list = lambdaQuery()
                .eq(ApduTable::getIns, INS)
                .list();

        //未查询到指令大致用途，直接返回null
        if (list.isEmpty()) {
            return apduTable;
        }

        if (list.size() == 1) {
            //获取指令
            //只有一条指令，可以通过INS直接判断出指令用途
            apduTable = list.get(0);
        }

        //查询到了多条指令，需要INS和P1共同判断指令用途
        if (list.size() > 1) {
            List<ApduTable> lists = lambdaQuery()
                    .eq(ApduTable::getIns, INS)
                    .eq(ApduTable::getP1, P1)
                    .list();
            apduTable = lists.get(0);
        }

        return apduTable;
    }

    /**
     * 指令中不存在aid的处理逻辑
     * @param apduTable
     * @param apdu
     * @return
     */
    private AjaxResult emptyAidResult(ApduTable apduTable, String apdu) {
        //创建返回对象，然后拼装结果
        ApduParseVo result = new ApduParseVo();

        result.setApdu(apdu);
        result.setApduDescription(apduTable.getDescription());

        //创建工厂
        SentenceStrategy sentenceStrategy = SentenceStrategyFactory.getStarategy(apduTable.getName());

        //创建一个工厂表单类，用来创建工厂
        SentenceFactoryDto factoryDto = new SentenceFactoryDto(apduTable.getName(), apdu);

        //获取拼接语句
        String sentence = sentenceStrategy.getSentenceOfapduName(factoryDto);

        //由于该指令不存在aid，不用进行拼装，所以直接返回拼接语句即可
        result.setApduRealUse(sentence);

        return AjaxResult.success(apduTable.getDescription(), result);
    }

    /**
     * 指令中存在aid的处理逻辑
     * @param aidInfos
     * @param apduTable
     * @param apdu
     * @return
     */
    private AjaxResult haveAidResult(List<AidInfo> aidInfos, ApduTable apduTable, String apdu) {
        //对集合aidInfos排序，根据level进行排序
        aidInfos.sort(Comparator.comparing(AidInfo::getLevel));

        //aidinfos中存放的即为指令中存在的aid
        log.info("aidInfos:{}", aidInfos.toString());

        //创建工厂
        SentenceStrategy sentenceStrategy = SentenceStrategyFactory.getStarategy(apduTable.getName());

        //创建一个工厂表单类，用来创建工厂
        SentenceFactoryDto factoryDto = SentenceFactoryDto.of(apduTable.getName(), apdu, aidInfos);

        //获取指令解析结果
        String apduRealUse = sentenceStrategy.getSentenceOfapduName(factoryDto);

        //创建vo封装数据
        ApduParseVo result = new ApduParseVo();
        result.setApdu(apdu);
        result.setApduDescription(apduTable.getDescription());
        result.setAidInfos(aidInfos);
        result.setApduRealUse(apduRealUse);

        return AjaxResult.success(apduTable.getDescription(), result);
    }



    /**
     * 判断指令中存在哪些aid
     *
     * @param aidTable
     * @param apdu
     * @return
     */
    private List<AidInfo> getAidInfo(AidTable aidTable, ApduTable apduTable, String apdu) {

        //拿取各个aid，同时判断aid是否存在，不存在的话置为-1
        String isd = getIsd();
        isd = isd == null ? "-1" : isd;

        //获取雪球AMSD的capaid以及实例aid
        AidTable snowBallAmsd = getSnowBallAmsd();
        String snowBallAmsdCap = snowBallAmsd.getCapAid();
        String snowBallamsdAid = snowBallAmsd.getAmsdAid();

        //获取三星AMSDcap
        AidTable sayAmsd  = getSayAmsd();
        String sayAmsdCap = sayAmsd.getCapAid();
        String sayAmsdAid = sayAmsd.getAmsdAid();

        //获取华为(SAAS)DMSD
        AidTable hwDmsd = getHwDmsd();
        String hwDmsdAid = hwDmsd.getAmsdAid();

        String mocAid = aidTable.getMocAid();
        mocAid = mocAid == null ? "-1" : mocAid;

        String ecAid = aidTable.getEcAid();
        ecAid = ecAid == null ? "-1" : ecAid;

        String epAid = aidTable.getEpAid();
        epAid = epAid == null ? "-1" : epAid;

        String capAid = aidTable.getCapAid();
        capAid = capAid == null ? "-1" : capAid;

        String ssdAid = aidTable.getSsdAid();
        ssdAid = ssdAid == null ? "-1" : ssdAid;

        String moduleAid = aidTable.getModuleAid();
        moduleAid = moduleAid == null ? "-1" : moduleAid;

        String modAid = aidTable.getModAid();
        modAid = modAid == null ? "-1" : modAid;


        //判断哪个aid在指令里存在，然后放入到集合中
        List<AidInfo> aidInfoList = new ArrayList<>();

        //判断ISD是否存在
        if (apdu.contains(isd)) {
            aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.ISD_LEVEL,
                    isd,
                    AidConstant.ISD_NAME,
                    apduTable.getDescription()));
        }

        //判断雪球AMSD
        if (apdu.contains(snowBallamsdAid)) {
            aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.AMSD_LEVEL,
                    snowBallamsdAid,
                    AidConstant.AMSD_NAME,
                    apduTable.getDescription()));
        }

        //判断雪球AMSD的cap是否存在
        if (apdu.contains(snowBallAmsdCap)) {
            aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.AMSD_LEVEL,
                    snowBallAmsdCap,
                    AidConstant.AMSD_NAME,
                    apduTable.getDescription()));
        }

        //判断三星AMSD
        if (apdu.contains(sayAmsdAid)) {
            aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.AMSD_LEVEL,
                    sayAmsdAid,
                    AidConstant.AMSD_NAME,
                    apduTable.getDescription()));
        }

        //判断三星AMSD的cap是否存在
        if (apdu.contains(sayAmsdCap)) {
            aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.AMSD_LEVEL,
                    sayAmsdCap,
                    AidConstant.AMSD_NAME,
                    apduTable.getDescription()));
        }

        //判断华为（SAAS）DMSD
        if (apdu.contains(hwDmsdAid)) {
            aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.AMSD_LEVEL,
                    hwDmsdAid,
                    AidConstant.AMSD_NAME,
                    apduTable.getDescription()));
        }

        //判断MOC
        if (apdu.contains(mocAid)) {
            aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.MOC_LEVEL,
                    mocAid,
                    AidConstant.MOC_NAME,
                    apduTable.getDescription()));
        }
        //判断EC
        if (apdu.contains(ecAid)) {
            aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.EC_LEVEL,
                    ecAid,
                    AidConstant.EC_NAME,
                    apduTable.getDescription()));
        }

        //判断EP
        if (apdu.contains(epAid)) {
            aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.EP_LEVEL,
                    epAid,
                    AidConstant.EP_NAME,
                    apduTable.getDescription()));
        }

        //判断CAP
        if (apdu.contains(capAid)) {
            aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.CAP_LEVEL,
                    capAid,
                    AidConstant.CAP_NAME,
                    apduTable.getDescription()));
        }

        //判断SSD
        if (apdu.contains(ssdAid)) {
            aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.SSD_LEVEL,
                    ssdAid,
                    AidConstant.SSD_NAME,
                    apduTable.getDescription()));
        }

        //判断MODULE
        if (apdu.contains(moduleAid)) {
            log.info("moduleAid:{},不做任何处理",moduleAid);
            /*aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.MODULE_LEVEL,
                    moduleAid,
                    AidConstant.MODULE_NAME,
                    apduTable.getDescription()));*/
        }

        //判断MOD
        if (apdu.contains(modAid)) {
            log.info("moduleAid:{},不做任何处理",moduleAid);
            /*aidInfoList.add(AidInfo.of(apduTable.getName(),
                    AidConstant.MOD_LEVEL,
                    modAid,
                    AidConstant.MOD_NAME,
                    apduTable.getDescription()));*/
        }

        return aidInfoList.stream().distinct().collect(Collectors.toList());

    }

    private AidTable getHwDmsd() {
        return aidTableService.lambdaQuery()
                .eq(AidTable::getAppCode, AidConstant.HUAWEI_DMSD)
                .one();
    }

    /**
     * 获取三星AmsdCap
     * @return
     */
    private AidTable getSayAmsd() {

        return aidTableService.lambdaQuery()
                .eq(AidTable::getAppCode, AidConstant.SAMSUNG_AMSD)
                .one();
    }

    /**
     * 获取AMSD的cap
     * @return
     */
    private AidTable getSnowBallAmsd() {
        AidTable snowBallAMSD = aidTableService.lambdaQuery()
                .eq(AidTable::getAppCode, AidConstant.AMSD)
                .one();

        return snowBallAMSD;
    }

    /**
     * 获取AID
     *
     * @param apduInfo
     * @return
     */
    private AidTable getAid(ApduInfoDto apduInfo) {

        return aidTableService.lambdaQuery()
                .eq(AidTable::getAppCode, apduInfo.getAppcode())
                .eq(AidTable::getIsSaas, apduInfo.getIsSaas())
                .eq(AidTable::getType, apduInfo.getType())
                .one();
    }

    /**
     * 获取ISD
     *
     * @return
     */
    private String getIsd() {
        AidTable aidTable = aidTableService.lambdaQuery()
                .eq(AidTable::getAppCode, AidConstant.ISD)
                .one();
        return aidTable.getMocAid();
    }
}
